#ifdef BKPT_SUPPORT
#define CONSOLE_OUTPUT(a, b) \
    extern void (*dbgOutput)(const char *, u32); \
    if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \
		dbgOutput((a), (b)); \
	}
#else
#define CONSOLE_OUTPUT(a, b)
#endif

#define OP_AND \
    reg[dest].I = reg[(opcode >> 16) & 15].I & value; \
    CONSOLE_OUTPUT(NULL, reg[2].I);

#define OP_ANDS \
    reg[dest].I = reg[(opcode >> 16) & 15].I & value; \
      \
    N_FLAG = (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG = (reg[dest].I) ? false : true; \
    C_FLAG = C_OUT;

#define OP_EOR \
    reg[dest].I = reg[(opcode >> 16) & 15].I ^ value;

#define OP_EORS \
    reg[dest].I = reg[(opcode >> 16) & 15].I ^ value; \
      \
    N_FLAG = (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG = (reg[dest].I) ? false : true; \
    C_FLAG = C_OUT;
#ifdef C_CORE
#define NEG(i) ((i) >> 31)
#define POS(i) ((~(i)) >> 31)
#define ADDCARRY(a, b, c) \
    C_FLAG = ((NEG(a) & NEG(b)) | \
              (NEG(a) & POS(c)) | \
              (NEG(b) & POS(c))) ? true : false;
#define ADDOVERFLOW(a, b, c) \
    V_FLAG = ((NEG(a) & NEG(b) & POS(c)) | \
              (POS(a) & POS(b) & NEG(c))) ? true : false;
#define SUBCARRY(a, b, c) \
    C_FLAG = ((NEG(a) & POS(b)) | \
              (NEG(a) & POS(c)) | \
              (POS(b) & POS(c))) ? true : false;
#define SUBOVERFLOW(a, b, c) \
    V_FLAG = ((NEG(a) & POS(b) & POS(c)) | \
              (POS(a) & NEG(b) & NEG(c))) ? true : false;
#define OP_SUB \
	{ \
		reg[dest].I = reg[base].I - value; \
	}
#define OP_SUBS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define OP_RSB \
	{ \
		reg[dest].I = value - reg[base].I; \
	}
#define OP_RSBS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = rhs - lhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(rhs, lhs, res); \
		SUBOVERFLOW(rhs, lhs, res); \
	}
#define OP_ADD \
	{ \
		reg[dest].I = reg[base].I + value; \
	}
#define OP_ADDS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define OP_ADC \
	{ \
		reg[dest].I = reg[base].I + value + (u32)C_FLAG; \
	}
#define OP_ADCS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs + (u32)C_FLAG; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define OP_SBC \
	{ \
		reg[dest].I = reg[base].I - value - !((u32)C_FLAG); \
	}
#define OP_SBCS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs - !((u32)C_FLAG); \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define OP_RSC \
	{ \
		reg[dest].I = value - reg[base].I - !((u32)C_FLAG); \
	}
#define OP_RSCS \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = rhs - lhs - !((u32)C_FLAG); \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(rhs, lhs, res); \
		SUBOVERFLOW(rhs, lhs, res); \
	}
#define OP_CMP \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs; \
		Z_FLAG = (res == 0) ? true : false; \
		N_FLAG = NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define OP_CMN \
	{ \
		u32 lhs = reg[base].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs; \
		Z_FLAG = (res == 0) ? true : false; \
		N_FLAG = NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}

#define LOGICAL_LSL_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
		value = v << shift; \
	}
#define LOGICAL_LSR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = v >> shift; \
	}
#define LOGICAL_ASR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false; \
		value = (s32)v >> (int)shift; \
	}
#define LOGICAL_ROR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
#define LOGICAL_RRX_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		shift = (int)C_FLAG; \
		C_OUT = (v  & 1) ? true : false; \
		value = ((v >> 1) | \
		         (shift << 31)); \
	}
#define LOGICAL_ROR_IMM \
	{ \
		u32 v = opcode & 0xff; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
#define ARITHMETIC_LSL_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = v << shift; \
	}
#define ARITHMETIC_LSR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = v >> shift; \
	}
#define ARITHMETIC_ASR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = (s32)v >> (int)shift; \
	}
#define ARITHMETIC_ROR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
#define ARITHMETIC_RRX_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		shift = (int)C_FLAG; \
		value = ((v >> 1) | \
		         (shift << 31)); \
	}
#define ARITHMETIC_ROR_IMM \
	{ \
		u32 v = opcode & 0xff; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
#define ROR_IMM_MSR \
	{ \
		u32 v = opcode & 0xff; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
#define ROR_VALUE \
	{ \
		value = ((value << (32 - shift)) | \
		         (value >> shift)); \
	}
#define RCR_VALUE \
	{ \
		shift = (int)C_FLAG; \
		value = ((value >> 1) | \
		         (shift << 31)); \
	}
#else
#ifdef __GNUC__
		#ifdef __POWERPC__
			#define OP_SUB \
	{ \
		reg[dest].I = reg[base].I - value; \
	}
			#define OP_SUBS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("subco. %0, %2, %3\n"              \
		              "mcrxr cr1\n"                       \
		              "mfcr %1\n"                         \
					  : "=r" (Result),                    \
		              "=r" (Flags)                      \
					  : "r" (reg[base].I),                \
		              "r" (value)                       \
		              );                                  \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_RSB \
	{ \
		reg[dest].I = value - reg[base].I; \
	}
			#define OP_RSBS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("subfco. %0, %2, %3\n"             \
		              "mcrxr cr1\n"                       \
		              "mfcr %1\n"                         \
					  : "=r" (Result),                    \
		              "=r" (Flags)                      \
					  : "r" (reg[base].I),                \
		              "r" (value)                       \
		              );                                  \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_ADD \
	{ \
		reg[dest].I = reg[base].I + value; \
	}

			#define OP_ADDS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("addco. %0, %2, %3\n"              \
		              "mcrxr cr1\n"                       \
		              "mfcr %1\n"                         \
					  : "=r" (Result),                    \
		              "=r" (Flags)                      \
					  : "r" (reg[base].I),                \
		              "r" (value)                       \
		              );                                  \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_ADC \
	{ \
		reg[dest].I = reg[base].I + value + (u32)C_FLAG; \
	}
			#define OP_ADCS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("mtspr xer, %4\n"                  \
		              "addeo. %0, %2, %3\n"              \
		              "mcrxr cr1\n"                      \
		              "mfcr      %1\n"                   \
					  : "=r" (Result),                   \
		              "=r" (Flags)                     \
					  : "r" (reg[base].I),               \
		              "r" (value),                     \
		              "r" (C_FLAG << 29)               \
		              );                                 \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_SBC \
	{ \
		reg[dest].I = reg[base].I - value - (C_FLAG ^ 1); \
	}
			#define OP_SBCS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("mtspr xer, %4\n"                  \
		              "subfeo. %0, %3, %2\n"             \
		              "mcrxr cr1\n"                      \
		              "mfcr      %1\n"                   \
					  : "=r" (Result),                   \
		              "=r" (Flags)                     \
					  : "r" (reg[base].I),               \
		              "r" (value),                     \
		              "r" (C_FLAG << 29)               \
		              );                                 \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_RSC \
	{ \
		reg[dest].I = value - reg[base].I - (C_FLAG ^ 1); \
	}
			#define OP_RSCS \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("mtspr xer, %4\n"                  \
		              "subfeo. %0, %2, %3\n"             \
		              "mcrxr cr1\n"                      \
		              "mfcr      %1\n"                   \
					  : "=r" (Result),                   \
		              "=r" (Flags)                     \
					  : "r" (reg[base].I),               \
		              "r" (value),                     \
		              "r" (C_FLAG << 29)               \
		              );                                 \
		reg[dest].I = Result;                           \
		Z_FLAG		= (Flags >> 29) & 1;                     \
		N_FLAG		= (Flags >> 31) & 1;                     \
		C_FLAG		= (Flags >> 25) & 1;                     \
		V_FLAG		= (Flags >> 26) & 1;                     \
	}
			#define OP_CMP \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("subco. %0, %2, %3\n"              \
		              "mcrxr cr1\n"                       \
		              "mfcr %1\n"                         \
					  : "=r" (Result),                    \
		              "=r" (Flags)                      \
					  : "r" (reg[base].I),                \
		              "r" (value)                       \
		              );                                  \
		Z_FLAG = (Flags >> 29) & 1;                     \
		N_FLAG = (Flags >> 31) & 1;                     \
		C_FLAG = (Flags >> 25) & 1;                     \
		V_FLAG = (Flags >> 26) & 1;                     \
	}
			#define OP_CMN \
	{ \
		register int Flags;                             \
		register int Result;                            \
		asm volatile ("addco. %0, %2, %3\n"              \
		              "mcrxr cr1\n"                       \
		              "mfcr %1\n"                         \
					  : "=r" (Result),                    \
		              "=r" (Flags)                      \
					  : "r" (reg[base].I),                \
		              "r" (value)                       \
		              );                                  \
		Z_FLAG = (Flags >> 29) & 1;                     \
		N_FLAG = (Flags >> 31) & 1;                     \
		C_FLAG = (Flags >> 25) & 1;                     \
		V_FLAG = (Flags >> 26) & 1;                     \
	}

			#define LOGICAL_LSL_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
		value = v << shift; \
	}
			#define LOGICAL_LSR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = v >> shift; \
	}
			#define LOGICAL_ASR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false; \
		value = (s32)v >> (int)shift; \
	}
			#define LOGICAL_ROR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
			#define LOGICAL_RRX_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		shift = (int)C_FLAG; \
		C_OUT = (v  & 1) ? true : false; \
		value = ((v >> 1) | \
		         (shift << 31)); \
	}
			#define LOGICAL_ROR_IMM \
	{ \
		u32 v = opcode & 0xff; \
		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
			#define ARITHMETIC_LSL_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = v << shift; \
	}
			#define ARITHMETIC_LSR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = v >> shift; \
	}
			#define ARITHMETIC_ASR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = (s32)v >> (int)shift; \
	}
			#define ARITHMETIC_ROR_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
			#define ARITHMETIC_RRX_REG \
	{ \
		u32 v = reg[opcode & 0x0f].I; \
		shift = (int)C_FLAG; \
		value = ((v >> 1) | \
		         (shift << 31)); \
	}
			#define ARITHMETIC_ROR_IMM \
	{ \
		u32 v = opcode & 0xff; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
			#define ROR_IMM_MSR \
	{ \
		u32 v = opcode & 0xff; \
		value = ((v << (32 - shift)) | \
		         (v >> shift)); \
	}
			#define ROR_VALUE \
	{ \
		value = ((value << (32 - shift)) | \
		         (value >> shift)); \
	}
			#define RCR_VALUE \
	{ \
		shift = (int)C_FLAG; \
		value = ((value >> 1) | \
		         (shift << 31)); \
	}
#else
#define OP_SUB \
    asm ("sub %1, %%ebx;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[base].I));

#define OP_SUBS \
    asm ("sub %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[base].I));

#define OP_RSB \
    asm  ("sub %1, %%ebx;" \
		  : "=b" (reg[dest].I) \
		  : "r" (reg[base].I), "b" (value));

#define OP_RSBS \
    asm  ("sub %1, %%ebx;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setncb C_FLAG;" \
          "setob V_FLAG;" \
		  : "=b" (reg[dest].I) \
		  : "r" (reg[base].I), "b" (value));

#define OP_ADD \
    asm  ("add %1, %%ebx;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));

#define OP_ADDS \
    asm  ("add %1, %%ebx;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setcb C_FLAG;" \
          "setob V_FLAG;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));

#define OP_ADC \
    asm  ("bt $0, C_FLAG;" \
          "adc %1, %%ebx;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));

#define OP_ADCS \
    asm  ("bt $0, C_FLAG;" \
          "adc %1, %%ebx;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setcb C_FLAG;" \
          "setob V_FLAG;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));

#define OP_SBC \
    asm  ("bt $0, C_FLAG;" \
          "cmc;" \
          "sbb %1, %%ebx;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));

#define OP_SBCS \
    asm  ("bt $0, C_FLAG;" \
          "cmc;" \
          "sbb %1, %%ebx;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setncb C_FLAG;" \
          "setob V_FLAG;" \
		  : "=b" (reg[dest].I) \
		  : "r" (value), "b" (reg[base].I));
#define OP_RSC \
    asm  ("bt $0, C_FLAG;" \
          "cmc;" \
          "sbb %1, %%ebx;" \
		  : "=b" (reg[dest].I) \
		  : "r" (reg[base].I), "b" (value));

#define OP_RSCS \
    asm  ("bt $0, C_FLAG;" \
          "cmc;" \
          "sbb %1, %%ebx;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setncb C_FLAG;" \
          "setob V_FLAG;" \
		  : "=b" (reg[dest].I) \
		  : "r" (reg[base].I), "b" (value));
#define OP_CMP \
    asm  ("sub %0, %1;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setncb C_FLAG;" \
          "setob V_FLAG;" \
		  : \
		  : "r" (value), "r" (reg[base].I));

#define OP_CMN \
    asm  ("add %0, %1;" \
          "setsb N_FLAG;" \
          "setzb Z_FLAG;" \
          "setcb C_FLAG;" \
          "setob V_FLAG;" \
		  : \
		  : "r" (value), "r" (reg[base].I));
#define LOGICAL_LSL_REG \
    asm ("shl %%cl, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define LOGICAL_LSR_REG \
    asm ("shr %%cl, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define LOGICAL_ASR_REG \
    asm ("sar %%cl, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define LOGICAL_ROR_REG \
    asm ("ror %%cl, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define LOGICAL_RRX_REG \
    asm ("bt $0, C_FLAG;" \
         "rcr $1, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (reg[opcode & 0x0f].I));

#define LOGICAL_ROR_IMM \
    asm ("ror %%cl, %%eax;" \
         "setcb %%cl;" \
		 : "=a" (value), "=c" (C_OUT) \
		 : "a" (opcode & 0xff), "c" (shift));
#define ARITHMETIC_LSL_REG \
    asm ("\
             shl %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define ARITHMETIC_LSR_REG \
    asm ("\
             shr %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define ARITHMETIC_ASR_REG \
    asm ("\
             sar %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define ARITHMETIC_ROR_REG \
    asm ("\
             ror %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (reg[opcode & 0x0f].I), "c" (shift));

#define ARITHMETIC_RRX_REG \
    asm ("\
             bt $0, C_FLAG;\
             rcr $1, %%eax;" \
		 : "=a" (value) \
		 : "a" (reg[opcode & 0x0f].I));

#define ARITHMETIC_ROR_IMM \
    asm ("\
             ror %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (opcode & 0xff), "c" (shift));
#define ROR_IMM_MSR \
    asm ("ror %%cl, %%eax;" \
		 : "=a" (value) \
		 : "a" (opcode & 0xFF), "c" (shift));
#define ROR_VALUE \
    asm ("ror %%cl, %0" \
		 : "=r" (value) \
		 : "r" (value), "c" (shift));
#define RCR_VALUE \
    asm ("bt $0, C_FLAG;" \
         "rcr $1, %0" \
		 : "=r" (value) \
		 : "r" (value));
#endif
#else
#define OP_SUB \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm sub ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
	}

#define OP_SUBS \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm sub ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}

#define OP_RSB \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm mov eax, value \
		__asm sub eax, ebx \
		__asm mov ebx, dest \
		__asm mov dword ptr [OFFSET reg + 4 * ebx], eax \
	}

#define OP_RSBS \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm mov eax, value \
		__asm sub eax, ebx \
		__asm mov ebx, dest \
		__asm mov dword ptr [OFFSET reg + 4 * ebx], eax \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}

#define OP_ADD \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm add ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
	}

#define OP_ADDS \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm add ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}

#define OP_ADC \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm bt word ptr C_FLAG, 0 \
		__asm adc ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
	}

#define OP_ADCS \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm bt word ptr C_FLAG, 0 \
		__asm adc ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}

#define OP_SBC \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm mov eax, value \
		__asm bt word ptr C_FLAG, 0 \
		__asm cmc \
		__asm sbb ebx, eax \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
	}

#define OP_SBCS \
	{ \
		__asm mov ebx, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm mov eax, value \
		__asm bt word ptr C_FLAG, 0 \
		__asm cmc \
		__asm sbb ebx, eax \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define OP_RSC \
	{ \
		__asm mov ebx, value \
		__asm mov eax, base \
		__asm mov eax, dword ptr[OFFSET reg + 4 * eax] \
		__asm bt word ptr C_FLAG, 0 \
		__asm cmc \
		__asm sbb ebx, eax \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
	}

#define OP_RSCS \
	{ \
		__asm mov ebx, value \
		__asm mov eax, base \
		__asm mov eax, dword ptr[OFFSET reg + 4 * eax] \
		__asm bt word ptr C_FLAG, 0 \
		__asm cmc \
		__asm sbb ebx, eax \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define OP_CMP \
	{ \
		__asm mov eax, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm sub ebx, value \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}

#define OP_CMN \
	{ \
		__asm mov eax, base \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm add ebx, value \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define LOGICAL_LSL_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm shl eax, cl \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT

#define LOGICAL_LSR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm shr eax, cl \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT

#define LOGICAL_ASR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm sar eax, cl \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT

#define LOGICAL_ROR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0F \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm ror eax, cl \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT

#define LOGICAL_RRX_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0F \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm bt word ptr C_OUT, 0 \
    __asm rcr eax, 1 \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT

#define LOGICAL_ROR_IMM \
    __asm mov eax, opcode \
    __asm and eax, 0xff \
    __asm mov cl, byte ptr shift \
    __asm ror eax, cl \
    __asm mov value, eax \
    __asm setc byte ptr C_OUT
#define ARITHMETIC_LSL_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm shl eax, cl \
    __asm mov value, eax

#define ARITHMETIC_LSR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm shr eax, cl \
    __asm mov value, eax

#define ARITHMETIC_ASR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0f \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm sar eax, cl \
    __asm mov value, eax

#define ARITHMETIC_ROR_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0F \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm mov cl, byte ptr shift \
    __asm ror eax, cl \
    __asm mov value, eax

#define ARITHMETIC_RRX_REG \
    __asm mov eax, opcode \
    __asm and eax, 0x0F \
    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
    __asm bt word ptr C_FLAG, 0 \
    __asm rcr eax, 1 \
    __asm mov value, eax

#define ARITHMETIC_ROR_IMM \
    __asm mov eax, opcode \
    __asm and eax, 0xff \
    __asm mov cl, byte ptr shift \
    __asm ror eax, cl \
    __asm mov value, eax
#define ROR_IMM_MSR \
	{ \
		__asm mov eax, opcode \
		          __asm and eax, 0xff \
		__asm mov cl, byte ptr shift \
		__asm ror eax, CL \
		__asm mov value, eax \
	}
#define ROR_VALUE \
	{ \
		__asm mov cl, byte ptr shift \
		__asm ror dword ptr value, cl \
	}
#define RCR_VALUE \
	{ \
		__asm mov cl, byte ptr shift \
		__asm bt word ptr C_FLAG, 0 \
		__asm rcr dword ptr value, 1 \
	}
#endif
#endif

#define OP_TST \
    u32 res = reg[base].I & value; \
    N_FLAG	= (res & 0x80000000) ? true : false; \
    Z_FLAG	= (res) ? false : true; \
    C_FLAG	= C_OUT;

#define OP_TEQ \
    u32 res = reg[base].I ^ value; \
    N_FLAG	= (res & 0x80000000) ? true : false; \
    Z_FLAG	= (res) ? false : true; \
    C_FLAG	= C_OUT;

#define OP_ORR \
    reg[dest].I = reg[base].I | value;

#define OP_ORRS \
    reg[dest].I = reg[base].I | value; \
    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG		= (reg[dest].I) ? false : true; \
    C_FLAG		= C_OUT;

#define OP_MOV \
    reg[dest].I = value;

#define OP_MOVS \
    reg[dest].I = value; \
    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG		= (reg[dest].I) ? false : true; \
    C_FLAG		= C_OUT;

#define OP_BIC \
    reg[dest].I = reg[base].I & (~value);

#define OP_BICS \
    reg[dest].I = reg[base].I & (~value); \
    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG		= (reg[dest].I) ? false : true; \
    C_FLAG		= C_OUT;

#define OP_MVN \
    reg[dest].I = ~value;

#define OP_MVNS \
    reg[dest].I = ~value; \
    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
    Z_FLAG		= (reg[dest].I) ? false : true; \
    C_FLAG		= C_OUT;

#define CASE_16(BASE) \
case BASE: \
case BASE + 1: \
case BASE + 2: \
case BASE + 3: \
case BASE + 4: \
case BASE + 5: \
case BASE + 6: \
case BASE + 7: \
case BASE + 8: \
case BASE + 9: \
case BASE + 10: \
case BASE + 11: \
case BASE + 12: \
case BASE + 13: \
case BASE + 14: \
case BASE + 15:

#define CASE_256(BASE) \
    CASE_16(BASE) \
    CASE_16(BASE + 0x10) \
    CASE_16(BASE + 0x20) \
    CASE_16(BASE + 0x30) \
    CASE_16(BASE + 0x40) \
    CASE_16(BASE + 0x50) \
    CASE_16(BASE + 0x60) \
    CASE_16(BASE + 0x70) \
    CASE_16(BASE + 0x80) \
    CASE_16(BASE + 0x90) \
    CASE_16(BASE + 0xa0) \
    CASE_16(BASE + 0xb0) \
    CASE_16(BASE + 0xc0) \
    CASE_16(BASE + 0xd0) \
    CASE_16(BASE + 0xe0) \
    CASE_16(BASE + 0xf0)

#define LOGICAL_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
case BASE: \
case BASE + 8: \
{ \
	/* OP Rd,Rb,Rm LSL # */ \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
      \
	if (shift) { \
		LOGICAL_LSL_REG \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 2: \
case BASE + 10: \
{ \
	/* OP Rd,Rb,Rm LSR # */ \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_LSR_REG \
	} else { \
		value = 0; \
		C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false; \
	} \
      \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 4: \
case BASE + 12: \
{ \
	/* OP Rd,Rb,Rm ASR # */ \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ASR_REG \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
			C_OUT = true; \
		} else { \
			value = 0; \
			C_OUT = false; \
		}                   \
	} \
      \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 6: \
case BASE + 14: \
{ \
	/* OP Rd,Rb,Rm ROR # */ \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ROR_REG \
	} else { \
		LOGICAL_RRX_REG \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 1: \
{ \
	/* OP Rd,Rb,Rm LSL Rs */ \
	clockTicks++; \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
			C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false); \
		} else if (shift < 32) { \
			LOGICAL_LSL_REG \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 3: \
{ \
	/* OP Rd,Rb,Rm LSR Rs */ \
	clockTicks++; \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
			C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false); \
		} else if (shift < 32) { \
			LOGICAL_LSR_REG \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 5: \
{ \
	/* OP Rd,Rb,Rm ASR Rs */ \
	clockTicks++; \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift < 32) { \
		if (shift) { \
			LOGICAL_ASR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
		} \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
			C_OUT = true; \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 7: \
{ \
	/* OP Rd,Rb,Rm ROR Rs */ \
	clockTicks++; \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		shift &= 0x1f; \
		if (shift) { \
			LOGICAL_ROR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
			C_OUT = (value & 0x80000000 ? true : false); \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
		C_OUT = (value & 0x80000000 ? true : false); \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 0x200: \
case BASE + 0x201: \
case BASE + 0x202: \
case BASE + 0x203: \
case BASE + 0x204: \
case BASE + 0x205: \
case BASE + 0x206: \
case BASE + 0x207: \
case BASE + 0x208: \
case BASE + 0x209: \
case BASE + 0x20a: \
case BASE + 0x20b: \
case BASE + 0x20c: \
case BASE + 0x20d: \
case BASE + 0x20e: \
case BASE + 0x20f: \
{ \
	int	 shift = (opcode & 0xF00) >> 7; \
	int	 base  = (opcode >> 16) & 0x0F; \
	int	 dest  = (opcode >> 12) & 0x0F; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ROR_IMM \
	} else { \
		value = opcode & 0xff; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break;

#define LOGICAL_DATA_OPCODE_WITHOUT_base(OPCODE, OPCODE2, BASE) \
case BASE: \
case BASE + 8: \
{ \
	/* OP Rd,Rb,Rm LSL # */ \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
      \
	if (shift) { \
		LOGICAL_LSL_REG \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 2: \
case BASE + 10: \
{ \
	/* OP Rd,Rb,Rm LSR # */ \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_LSR_REG \
	} else { \
		value = 0; \
		C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false; \
	} \
      \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 4: \
case BASE + 12: \
{ \
	/* OP Rd,Rb,Rm ASR # */ \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ASR_REG \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
			C_OUT = true; \
		} else { \
			value = 0; \
			C_OUT = false; \
		}                   \
	} \
      \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 6: \
case BASE + 14: \
{ \
	/* OP Rd,Rb,Rm ROR # */ \
	int	 shift = (opcode >> 7) & 0x1F; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ROR_REG \
	} else { \
		LOGICAL_RRX_REG \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 1: \
{ \
	/* OP Rd,Rb,Rm LSL Rs */ \
	clockTicks++; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
			C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false); \
		} else if (shift < 32) { \
			LOGICAL_LSL_REG \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 3: \
{ \
	/* OP Rd,Rb,Rm LSR Rs */ \
	clockTicks++; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
			C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false); \
		} else if (shift < 32) { \
			LOGICAL_LSR_REG \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 5: \
{ \
	/* OP Rd,Rb,Rm ASR Rs */ \
	clockTicks++; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift < 32) { \
		if (shift) { \
			LOGICAL_ASR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
		} \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
			C_OUT = true; \
		} else { \
			value = 0; \
			C_OUT = false; \
		} \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 7: \
{ \
	/* OP Rd,Rb,Rm ROR Rs */ \
	clockTicks++; \
	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
	int	 dest  = (opcode >> 12) & 15; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		shift &= 0x1f; \
		if (shift) { \
			LOGICAL_ROR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
			C_OUT = (value & 0x80000000 ? true : false); \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
		C_OUT = (value & 0x80000000 ? true : false); \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 0x200: \
case BASE + 0x201: \
case BASE + 0x202: \
case BASE + 0x203: \
case BASE + 0x204: \
case BASE + 0x205: \
case BASE + 0x206: \
case BASE + 0x207: \
case BASE + 0x208: \
case BASE + 0x209: \
case BASE + 0x20a: \
case BASE + 0x20b: \
case BASE + 0x20c: \
case BASE + 0x20d: \
case BASE + 0x20e: \
case BASE + 0x20f: \
{ \
	int	 shift = (opcode & 0xF00) >> 7; \
	int	 dest  = (opcode >> 12) & 0x0F; \
	bool C_OUT = C_FLAG; \
	u32	 value; \
	if (shift) { \
		LOGICAL_ROR_IMM \
	} else { \
		value = opcode & 0xff; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break;

#define ARITHMETIC_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
case BASE: \
case BASE + 8: \
{ \
	/* OP Rd,Rb,Rm LSL # */ \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = (opcode >> 7) & 0x1F; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		ARITHMETIC_LSL_REG \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 2: \
case BASE + 10: \
{ \
	/* OP Rd,Rb,Rm LSR # */ \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = (opcode >> 7) & 0x1F; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		ARITHMETIC_LSR_REG \
	} else { \
		value = 0; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 4: \
case BASE + 12: \
{ \
	/* OP Rd,Rb,Rm ASR # */ \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = (opcode >> 7) & 0x1F; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		ARITHMETIC_ASR_REG \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
		} else value = 0; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 6: \
case BASE + 14: \
{ \
	/* OP Rd,Rb,Rm ROR # */ \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = (opcode >> 7) & 0x1F; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		ARITHMETIC_ROR_REG \
	} else { \
		ARITHMETIC_RRX_REG \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 1: \
{ \
	/* OP Rd,Rb,Rm LSL Rs */ \
	clockTicks++; \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = reg[(opcode >> 8) & 15].B.B0; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
		} else if (shift < 32) { \
			ARITHMETIC_LSL_REG \
		} else value = 0; \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 3: \
{ \
	/* OP Rd,Rb,Rm LSR Rs */ \
	clockTicks++; \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = reg[(opcode >> 8) & 15].B.B0; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		if (shift == 32) { \
			value = 0; \
		} else if (shift < 32) { \
			ARITHMETIC_LSR_REG \
		} else value = 0; \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 5: \
{ \
	/* OP Rd,Rb,Rm ASR Rs */ \
	clockTicks++; \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = reg[(opcode >> 8) & 15].B.B0; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift < 32) { \
		if (shift) { \
			ARITHMETIC_ASR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
		} \
	} else { \
		if (reg[opcode & 0x0F].I & 0x80000000) { \
			value = 0xFFFFFFFF; \
		} else value = 0; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 7: \
{ \
	/* OP Rd,Rb,Rm ROR Rs */ \
	clockTicks++; \
	int base  = (opcode >> 16) & 0x0F; \
	int shift = reg[(opcode >> 8) & 15].B.B0; \
	int dest  = (opcode >> 12) & 15; \
	u32 value; \
	if (shift) { \
		shift &= 0x1f; \
		if (shift) { \
			ARITHMETIC_ROR_REG \
		} else { \
			value = reg[opcode & 0x0F].I; \
		} \
	} else { \
		value = reg[opcode & 0x0F].I; \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break; \
case BASE + 0x200: \
case BASE + 0x201: \
case BASE + 0x202: \
case BASE + 0x203: \
case BASE + 0x204: \
case BASE + 0x205: \
case BASE + 0x206: \
case BASE + 0x207: \
case BASE + 0x208: \
case BASE + 0x209: \
case BASE + 0x20a: \
case BASE + 0x20b: \
case BASE + 0x20c: \
case BASE + 0x20d: \
case BASE + 0x20e: \
case BASE + 0x20f: \
{ \
	int shift = (opcode & 0xF00) >> 7; \
	int base  = (opcode >> 16) & 0x0F; \
	int dest  = (opcode >> 12) & 0x0F; \
	u32 value; \
	{ \
		ARITHMETIC_ROR_IMM \
	} \
	if (dest == 15) { \
		OPCODE2 \
		/* todo */ \
		if (opcode & 0x00100000) { \
			clockTicks++; \
			CPUSwitchMode(reg[17].I & 0x1f, false); \
		} \
		if (armState) { \
			reg[15].I &= 0xFFFFFFFC; \
			armNextPC  = reg[15].I; \
			reg[15].I += 4; \
		} else { \
			reg[15].I &= 0xFFFFFFFE; \
			armNextPC  = reg[15].I; \
			reg[15].I += 2; \
		} \
	} else { \
		OPCODE \
	} \
} \
break;

u32 opcode = CPUReadMemoryQuick(armNextPC);

clockTicks = memoryWaitFetch32[(armNextPC >> 24) & 15];

#ifndef FINAL_VERSION
if (armNextPC == armStopAddr)
{
	armNextPC++;
}
#endif

armNextPC  = reg[15].I;
reg[15].I += 4;
int cond = opcode >> 28;
// suggested optimization for frequent cases
bool cond_res;
if (cond == 0x0e)
{
	cond_res = true;
}
else
{
	switch (cond)
	{
	case 0x00: // EQ
		cond_res = Z_FLAG;
		break;
	case 0x01: // NE
		cond_res = !Z_FLAG;
		break;
	case 0x02: // CS
		cond_res = C_FLAG;
		break;
	case 0x03: // CC
		cond_res = !C_FLAG;
		break;
	case 0x04: // MI
		cond_res = N_FLAG;
		break;
	case 0x05: // PL
		cond_res = !N_FLAG;
		break;
	case 0x06: // VS
		cond_res = V_FLAG;
		break;
	case 0x07: // VC
		cond_res = !V_FLAG;
		break;
	case 0x08: // HI
		cond_res = C_FLAG && !Z_FLAG;
		break;
	case 0x09: // LS
		cond_res = !C_FLAG || Z_FLAG;
		break;
	case 0x0A: // GE
		cond_res = N_FLAG == V_FLAG;
		break;
	case 0x0B: // LT
		cond_res = N_FLAG != V_FLAG;
		break;
	case 0x0C: // GT
		cond_res = !Z_FLAG && (N_FLAG == V_FLAG);
		break;
	case 0x0D: // LE
		cond_res = Z_FLAG || (N_FLAG != V_FLAG);
		break;
	case 0x0E:
		cond_res = true;
		break;
	case 0x0F:
	default:
		// ???
		cond_res = false;
		break;
	}
}

if (cond_res)
{
	switch (((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x0F))
	{
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_AND,  OP_AND, 0x000);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_ANDS, OP_AND, 0x010);
	case 0x009:
	{
		// MUL Rd, Rm, Rs
		int dest = (opcode >> 16) & 0x0F;
		int mult = (opcode & 0x0F);
		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
		reg[dest].I = reg[mult].I * rs;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
	case 0x019:
	{
		// MULS Rd, Rm, Rs
		int dest = (opcode >> 16) & 0x0F;
		int mult = (opcode & 0x0F);
		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
		reg[dest].I = reg[mult].I * rs;
		N_FLAG		= (reg[dest].I & 0x80000000) ? true : false;
		Z_FLAG		= (reg[dest].I) ? false : true;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
	case 0x00b:
	case 0x02b:
	{
		// STRH Rd, [Rn], -Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		address	   -= offset;
		reg[base].I = address;
	}
	break;
	case 0x04b:
	case 0x06b:
	{
		// STRH Rd, [Rn], #-offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		address	   -= offset;
		reg[base].I = address;
	}
	break;
	case 0x08b:
	case 0x0ab:
	{
		// STRH Rd, [Rn], Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		address	   += offset;
		reg[base].I = address;
	}
	break;
	case 0x0cb:
	case 0x0eb:
	{
		// STRH Rd, [Rn], #offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		address	   += offset;
		reg[base].I = address;
	}
	break;
	case 0x10b:
	{
		// STRH Rd, [Rn, -Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
	}
	break;
	case 0x12b:
	{
		// STRH Rd, [Rn, -Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		reg[base].I = address;
	}
	break;
	case 0x14b:
	{
		// STRH Rd, [Rn, -#offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
	}
	break;
	case 0x16b:
	{
		// STRH Rd, [Rn, -#offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		reg[base].I = address;
	}
	break;
	case 0x18b:
	{
		// STRH Rd, [Rn, Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
	}
	break;
	case 0x1ab:
	{
		// STRH Rd, [Rn, Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		reg[base].I = address;
	}
	break;
	case 0x1cb:
	{
		// STRH Rd, [Rn, #offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
	}
	break;
	case 0x1eb:
	{
		// STRH Rd, [Rn, #offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 4 + CPUUpdateTicksAccess16(address);
		CPUWriteHalfWord(address, reg[dest].W.W0);
		reg[base].I = address;
	}
	break;
	case 0x01b:
	case 0x03b:
	{
		// LDRH Rd, [Rn], -Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x05b:
	case 0x07b:
	{
		// LDRH Rd, [Rn], #-offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x09b:
	case 0x0bb:
	{
		// LDRH Rd, [Rn], Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x0db:
	case 0x0fb:
	{
		// LDRH Rd, [Rn], #offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x11b:
	{
		// LDRH Rd, [Rn, -Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
	}
	break;
	case 0x13b:
	{
		// LDRH Rd, [Rn, -Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x15b:
	{
		// LDRH Rd, [Rn, -#offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
	}
	break;
	case 0x17b:
	{
		// LDRH Rd, [Rn, -#offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x19b:
	{
		// LDRH Rd, [Rn, Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
	}
	break;
	case 0x1bb:
	{
		// LDRH Rd, [Rn, Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x1db:
	{
		// LDRH Rd, [Rn, #offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
	}
	break;
	case 0x1fb:
	{
		// LDRH Rd, [Rn, #offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = CPUReadHalfWord(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x01d:
	case 0x03d:
	{
		// LDRSB Rd, [Rn], -Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x05d:
	case 0x07d:
	{
		// LDRSB Rd, [Rn], #-offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x09d:
	case 0x0bd:
	{
		// LDRSB Rd, [Rn], Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x0dd:
	case 0x0fd:
	{
		// LDRSB Rd, [Rn], #offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x11d:
	{
		// LDRSB Rd, [Rn, -Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
	}
	break;
	case 0x13d:
	{
		// LDRSB Rd, [Rn, -Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x15d:
	{
		// LDRSB Rd, [Rn, -#offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
	}
	break;
	case 0x17d:
	{
		// LDRSB Rd, [Rn, -#offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x19d:
	{
		// LDRSB Rd, [Rn, Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
	}
	break;
	case 0x1bd:
	{
		// LDRSB Rd, [Rn, Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x1dd:
	{
		// LDRSB Rd, [Rn, #offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
	}
	break;
	case 0x1fd:
	{
		// LDRSB Rd, [Rn, #offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s8)CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x01f:
	case 0x03f:
	{
		// LDRSH Rd, [Rn], -Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x05f:
	case 0x07f:
	{
		// LDRSH Rd, [Rn], #-offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
		{
			address	   -= offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x09f:
	case 0x0bf:
	{
		// LDRSH Rd, [Rn], Rm
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x0df:
	case 0x0ff:
	{
		// LDRSH Rd, [Rn], #offset
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I;
		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
		{
			address	   += offset;
			reg[base].I = address;
		}
	}
	break;
	case 0x11f:
	{
		// LDRSH Rd, [Rn, -Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
	}
	break;
	case 0x13f:
	{
		// LDRSH Rd, [Rn, -Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x15f:
	{
		// LDRSH Rd, [Rn, -#offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
	}
	break;
	case 0x17f:
	{
		// LDRSH Rd, [Rn, -#offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x19f:
	{
		// LDRSH Rd, [Rn, Rm]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
	}
	break;
	case 0x1bf:
	{
		// LDRSH Rd, [Rn, Rm]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + reg[opcode & 0x0F].I;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
	case 0x1df:
	{
		// LDRSH Rd, [Rn, #offset]
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
	}
	break;
	case 0x1ff:
	{
		// LDRSH Rd, [Rn, #offset]!
		int base	= (opcode >> 16) & 0x0F;
		int dest	= (opcode >> 12) & 0x0F;
		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
		if (dest != base)
			reg[base].I = address;
	}
	break;
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EOR,  OP_EOR, 0x020);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EORS, OP_EOR, 0x030);
	case 0x029:
	{
		// MLA Rd, Rm, Rs, Rn
		int dest = (opcode >> 16) & 0x0F;
		int mult = (opcode & 0x0F);
		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
		reg[dest].I = reg[mult].I * rs + reg[(opcode >> 12) & 0x0f].I;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
	case 0x039:
	{
		// MLAS Rd, Rm, Rs, Rn
		int dest = (opcode >> 16) & 0x0F;
		int mult = (opcode & 0x0F);
		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
		reg[dest].I = reg[mult].I * rs + reg[(opcode >> 12) & 0x0f].I;
		N_FLAG		= (reg[dest].I & 0x80000000) ? true : false;
		Z_FLAG		= (reg[dest].I) ? false : true;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_SUB,  OP_SUB, 0x040);
		ARITHMETIC_DATA_OPCODE(OP_SUBS, OP_SUB, 0x050);
		ARITHMETIC_DATA_OPCODE(OP_RSB,  OP_RSB, 0x060);
		ARITHMETIC_DATA_OPCODE(OP_RSBS, OP_RSB, 0x070);
		ARITHMETIC_DATA_OPCODE(OP_ADD,  OP_ADD, 0x080);
		ARITHMETIC_DATA_OPCODE(OP_ADDS, OP_ADD, 0x090);
	case 0x089:
	{
		// UMULL RdLo, RdHi, Rn, Rs
		u32 umult	= reg[(opcode & 0x0F)].I;
		u32 usource = reg[(opcode >> 8) & 0x0F].I;
		int destLo	= (opcode >> 12) & 0x0F;
		int destHi	= (opcode >> 16) & 0x0F;
		u64 uTemp	= ((u64)umult) * ((u64)usource);
		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(uTemp >> 32);
		if ((usource & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((usource & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((usource & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
	case 0x099:
	{
		// UMULLS RdLo, RdHi, Rn, Rs
		u32 umult	= reg[(opcode & 0x0F)].I;
		u32 usource = reg[(opcode >> 8) & 0x0F].I;
		int destLo	= (opcode >> 12) & 0x0F;
		int destHi	= (opcode >> 16) & 0x0F;
		u64 uTemp	= ((u64)umult) * ((u64)usource);
		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(uTemp >> 32);
		Z_FLAG		  = (uTemp) ? false : true;
		N_FLAG		  = (reg[destHi].I & 0x80000000) ? true : false;
		if ((usource & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((usource & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((usource & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_ADC,  OP_ADC, 0x0a0);
		ARITHMETIC_DATA_OPCODE(OP_ADCS, OP_ADC, 0x0b0);
	case 0x0a9:
	{
		// UMLAL RdLo, RdHi, Rn, Rs
		u32 umult	= reg[(opcode & 0x0F)].I;
		u32 usource = reg[(opcode >> 8) & 0x0F].I;
		int destLo	= (opcode >> 12) & 0x0F;
		int destHi	= (opcode >> 16) & 0x0F;
		u64 uTemp	= (u64)reg[destHi].I;
		uTemp		<<= 32;
		uTemp		 |= (u64)reg[destLo].I;
		uTemp		 += ((u64)umult) * ((u64)usource);
		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(uTemp >> 32);
		if ((usource & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((usource & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((usource & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
	case 0x0b9:
	{
		// UMLALS RdLo, RdHi, Rn, Rs
		u32 umult	= reg[(opcode & 0x0F)].I;
		u32 usource = reg[(opcode >> 8) & 0x0F].I;
		int destLo	= (opcode >> 12) & 0x0F;
		int destHi	= (opcode >> 16) & 0x0F;
		u64 uTemp	= (u64)reg[destHi].I;
		uTemp		<<= 32;
		uTemp		 |= (u64)reg[destLo].I;
		uTemp		 += ((u64)umult) * ((u64)usource);
		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(uTemp >> 32);
		Z_FLAG		  = (uTemp) ? false : true;
		N_FLAG		  = (reg[destHi].I & 0x80000000) ? true : false;
		if ((usource & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((usource & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((usource & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_SBC,  OP_SBC, 0x0c0);
		ARITHMETIC_DATA_OPCODE(OP_SBCS, OP_SBC, 0x0d0);
	case 0x0c9:
	{
		// SMULL RdLo, RdHi, Rm, Rs
		int destLo = (opcode >> 12) & 0x0F;
		int destHi = (opcode >> 16) & 0x0F;
		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
		s64 s	   = (s32)rs;
		s64 sTemp  = m * s;
		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(sTemp >> 32);
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
	case 0x0d9:
	{
		// SMULLS RdLo, RdHi, Rm, Rs
		int destLo = (opcode >> 12) & 0x0F;
		int destHi = (opcode >> 16) & 0x0F;
		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
		s64 s	   = (s32)rs;
		s64 sTemp  = m * s;
		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(sTemp >> 32);
		Z_FLAG		  = (sTemp) ? false : true;
		N_FLAG		  = (sTemp < 0) ? true : false;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 2;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 3;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 4;
		else
			clockTicks += 5;
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_RSC,  OP_RSC, 0x0e0);
		ARITHMETIC_DATA_OPCODE(OP_RSCS, OP_RSC, 0x0f0);
	case 0x0e9:
	{
		// SMLAL RdLo, RdHi, Rm, Rs
		int destLo = (opcode >> 12) & 0x0F;
		int destHi = (opcode >> 16) & 0x0F;
		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
		s64 s	   = (s32)rs;
		s64 sTemp  = (u64)reg[destHi].I;
		sTemp		<<= 32;
		sTemp		 |= (u64)reg[destLo].I;
		sTemp		 += m * s;
		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(sTemp >> 32);
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
	case 0x0f9:
	{
		// SMLALS RdLo, RdHi, Rm, Rs
		int destLo = (opcode >> 12) & 0x0F;
		int destHi = (opcode >> 16) & 0x0F;
		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
		s64 s	   = (s32)rs;
		s64 sTemp  = (u64)reg[destHi].I;
		sTemp		<<= 32;
		sTemp		 |= (u64)reg[destLo].I;
		sTemp		 += m * s;
		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
		reg[destHi].I = (u32)(sTemp >> 32);
		Z_FLAG		  = (sTemp) ? false : true;
		N_FLAG		  = (sTemp < 0) ? true : false;
		if (((s32)rs) < 0)
			rs = ~rs;
		if ((rs & 0xFFFFFF00) == 0)
			clockTicks += 3;
		else if ((rs & 0xFFFF0000) == 0)
			clockTicks += 4;
		else if ((rs & 0xFF000000) == 0)
			clockTicks += 5;
		else
			clockTicks += 6;
	}
	break;
		LOGICAL_DATA_OPCODE(OP_TST, OP_TST, 0x110);
	case 0x100:
		// MRS Rd, CPSR
		// TODO: check if right instruction....
		CPUUpdateCPSR();
		reg[(opcode >> 12) & 0x0F].I = reg[16].I;
		break;
	case 0x109:
	{
		// SWP Rd, Rm, [Rn]
		u32 address = reg[(opcode >> 16) & 15].I;
		u32 temp	= CPUReadMemory(address);
		CPUWriteMemory(address, reg[opcode & 15].I);
		reg[(opcode >> 12) & 15].I = temp;
	}
	break;
		LOGICAL_DATA_OPCODE(OP_TEQ, OP_TEQ, 0x130);
	case 0x120:
	{
		// MSR CPSR_fields, Rm
		CPUUpdateCPSR();
		u32 value	 = reg[opcode & 15].I;
		u32 newValue = reg[16].I;
		if (armMode > 0x10)
		{
			if (opcode & 0x00010000)
				newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
			if (opcode & 0x00020000)
				newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
			if (opcode & 0x00040000)
				newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
		}
		if (opcode & 0x00080000)
			newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
		newValue |= 0x10;
		CPUSwitchMode(newValue & 0x1f, false);
		reg[16].I = newValue;
		CPUUpdateFlags();
	}
	break;
	case 0x121:
	{
		// BX Rm
		// TODO: check if right instruction...
		clockTicks += 3;
		int base = opcode & 0x0F;
		armState = reg[base].I & 1 ? false : true;
		if (armState)
		{
			reg[15].I  = reg[base].I & 0xFFFFFFFC;
			armNextPC  = reg[15].I;
			reg[15].I += 4;
		}
		else
		{
			reg[15].I  = reg[base].I & 0xFFFFFFFE;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
		}
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_CMP, OP_CMP, 0x150);
	case 0x140:
		// MRS Rd, SPSR
		// TODO: check if right instruction...
		reg[(opcode >> 12) & 0x0F].I = reg[17].I;
		break;
	case 0x149:
	{
		// SWPB Rd, Rm, [Rn]
		u32 address = reg[(opcode >> 16) & 15].I;
		u32 temp	= CPUReadByte(address);
		CPUWriteByte(address, reg[opcode & 15].B.B0);
		reg[(opcode >> 12) & 15].I = temp;
	}
	break;
		ARITHMETIC_DATA_OPCODE(OP_CMN, OP_CMN, 0x170);
	case 0x160:
	{
		// MSR SPSR_fields, Rm
		u32 value = reg[opcode & 15].I;
		if (armMode > 0x10 && armMode < 0x1f)
		{
			if (opcode & 0x00010000)
				reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
			if (opcode & 0x00020000)
				reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
			if (opcode & 0x00040000)
				reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
			if (opcode & 0x00080000)
				reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
		}
	}
	break;
		LOGICAL_DATA_OPCODE(OP_ORR,  OP_ORR, 0x180);
		LOGICAL_DATA_OPCODE(OP_ORRS, OP_ORR, 0x190);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOV,  OP_MOV, 0x1a0);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOVS, OP_MOV, 0x1b0);
		LOGICAL_DATA_OPCODE(OP_BIC,  OP_BIC, 0x1c0);
		LOGICAL_DATA_OPCODE(OP_BICS, OP_BIC, 0x1d0);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVN,  OP_MVN, 0x1e0);
		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVNS, OP_MVN, 0x1f0);
#ifdef BKPT_SUPPORT
	case 0x127:
	case 0x7ff: // for GDB support
		extern void (*dbgSignal)(int, int);
		reg[15].I -= 4;
		armNextPC -= 4;
		dbgSignal(5, (opcode & 0x0f) | ((opcode >> 4) & 0xfff0));
		return;
#endif
	case 0x320:
	case 0x321:
	case 0x322:
	case 0x323:
	case 0x324:
	case 0x325:
	case 0x326:
	case 0x327:
	case 0x328:
	case 0x329:
	case 0x32a:
	case 0x32b:
	case 0x32c:
	case 0x32d:
	case 0x32e:
	case 0x32f:
	{
		// MSR CPSR_fields, #
		CPUUpdateCPSR();
		u32 value = opcode & 0xFF;
		int shift = (opcode & 0xF00) >> 7;
		if (shift)
		{
			ROR_IMM_MSR;
		}
		u32 newValue = reg[16].I;
		if (armMode > 0x10)
		{
			if (opcode & 0x00010000)
				newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
			if (opcode & 0x00020000)
				newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
			if (opcode & 0x00040000)
				newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
		}
		if (opcode & 0x00080000)
			newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);

		newValue |= 0x10;

		CPUSwitchMode(newValue & 0x1f, false);
		reg[16].I = newValue;
		CPUUpdateFlags();
	}
	break;
	case 0x360:
	case 0x361:
	case 0x362:
	case 0x363:
	case 0x364:
	case 0x365:
	case 0x366:
	case 0x367:
	case 0x368:
	case 0x369:
	case 0x36a:
	case 0x36b:
	case 0x36c:
	case 0x36d:
	case 0x36e:
	case 0x36f:
	{
		// MSR SPSR_fields, #
		if (armMode > 0x10 && armMode < 0x1f)
		{
			u32 value = opcode & 0xFF;
			int shift = (opcode & 0xF00) >> 7;
			if (shift)
			{
				ROR_IMM_MSR;
			}
			if (opcode & 0x00010000)
				reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
			if (opcode & 0x00020000)
				reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
			if (opcode & 0x00040000)
				reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
			if (opcode & 0x00080000)
				reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
		}
	}
	break;
		CASE_16(0x400)
		// T versions shouldn't be different on GBA
		CASE_16(0x420)
		{
			// STR Rd, [Rn], -#
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			CPUWriteMemory(address, reg[dest].I);
			reg[base].I = address - offset;
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x480)
		// T versions shouldn't be different on GBA
		CASE_16(0x4a0)
		{
			// STR Rd, [Rn], #
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			CPUWriteMemory(address, reg[dest].I);
			reg[base].I = address + offset;
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x500)
		{
			// STR Rd, [Rn, -#]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			CPUWriteMemory(address, reg[dest].I);
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x520)
		{
			// STR Rd, [Rn, -#]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[base].I = address;
			CPUWriteMemory(address, reg[dest].I);
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x580)
		{
			// STR Rd, [Rn, #]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			CPUWriteMemory(address, reg[dest].I);
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x5a0)
		{
			// STR Rd, [Rn, #]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[base].I = address;
			CPUWriteMemory(address, reg[dest].I);
			clockTicks += 2 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x410)
		{
			// LDR Rd, [Rn], -#
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I -= offset;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x430)
		{
			// LDRT Rd, [Rn], -#
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I -= offset;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x490)
		{
			// LDR Rd, [Rn], #
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I += offset;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x4b0)
		{
			// LDRT Rd, [Rn], #
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I += offset;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
		}
		break;
		CASE_16(0x510)
		{
			// LDR Rd, [Rn, -#]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[dest].I = CPUReadMemory(address);
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x530)
		{
			// LDR Rd, [Rn, -#]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I = address;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x590)
		{
			// LDR Rd, [Rn, #]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[dest].I = CPUReadMemory(address);
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x5b0)
		{
			// LDR Rd, [Rn, #]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[dest].I = CPUReadMemory(address);
			if (dest != base)
				reg[base].I = address;
			clockTicks += 3 + CPUUpdateTicksAccess32(address);
			if (dest == 15)
			{
				clockTicks += 2;
				reg[15].I  &= 0xFFFFFFFC;
				armNextPC	= reg[15].I;
				reg[15].I  += 4;
			}
		}
		break;
		CASE_16(0x440)
		// T versions shouldn't be different on GBA
		CASE_16(0x460)
		{
			// STRB Rd, [Rn], -#
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			CPUWriteByte(address, reg[dest].B.B0);
			reg[base].I = address - offset;
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x4c0)
		// T versions shouldn't be different on GBA
		CASE_16(0x4e0)
		// STRB Rd, [Rn], #
		{
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			CPUWriteByte(address, reg[dest].B.B0);
			reg[base].I = address + offset;
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x540)
		{
			// STRB Rd, [Rn, -#]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			CPUWriteByte(address, reg[dest].B.B0);
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x560)
		{
			// STRB Rd, [Rn, -#]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[base].I = address;
			CPUWriteByte(address, reg[dest].B.B0);
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x5c0)
		{
			// STRB Rd, [Rn, #]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			CPUWriteByte(address, reg[dest].B.B0);
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x5e0)
		{
			// STRB Rd, [Rn, #]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[base].I = address;
			CPUWriteByte(address, reg[dest].I);
			clockTicks += 2 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x450)
		// T versions shouldn't be different
		CASE_16(0x470)
		{
			// LDRB Rd, [Rn], -#
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadByte(address);
			if (dest != base)
				reg[base].I -= offset;
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x4d0)
		CASE_16(0x4f0) // T versions should not be different
		{
			// LDRB Rd, [Rn], #
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I;
			reg[dest].I = CPUReadByte(address);
			if (dest != base)
				reg[base].I += offset;
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x550)
		{
			// LDRB Rd, [Rn, -#]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[dest].I = CPUReadByte(address);
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x570)
		{
			// LDRB Rd, [Rn, -#]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I - offset;
			reg[dest].I = CPUReadByte(address);
			if (dest != base)
				reg[base].I = address;
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x5d0)
		{
			// LDRB Rd, [Rn, #]
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[dest].I = CPUReadByte(address);
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
		CASE_16(0x5f0)
		{
			// LDRB Rd, [Rn, #]!
			int offset	= opcode & 0xFFF;
			int dest	= (opcode >> 12) & 15;
			int base	= (opcode >> 16) & 15;
			u32 address = reg[base].I + offset;
			reg[dest].I = CPUReadByte(address);
			if (dest != base)
				reg[base].I = address;
			clockTicks += 3 + CPUUpdateTicksAccess16(address);
		}
		break;
	case 0x600:
	case 0x608:
	// T versions are the same
	case 0x620:
	case 0x628:
	{
		// STR Rd, [Rn], -Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x602:
	case 0x60a:
	// T versions are the same
	case 0x622:
	case 0x62a:
	{
		// STR Rd, [Rn], -Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x604:
	case 0x60c:
	// T versions are the same
	case 0x624:
	case 0x62c:
	{
		// STR Rd, [Rn], -Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x606:
	case 0x60e:
	// T versions are the same
	case 0x626:
	case 0x62e:
	{
		// STR Rd, [Rn], -Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address - value;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x680:
	case 0x688:
	// T versions are the same
	case 0x6a0:
	case 0x6a8:
	{
		// STR Rd, [Rn], Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x682:
	case 0x68a:
	// T versions are the same
	case 0x6a2:
	case 0x6aa:
	{
		// STR Rd, [Rn], Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x684:
	case 0x68c:
	// T versions are the same
	case 0x6a4:
	case 0x6ac:
	{
		// STR Rd, [Rn], Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x686:
	case 0x68e:
	// T versions are the same
	case 0x6a6:
	case 0x6ae:
	{
		// STR Rd, [Rn], Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteMemory(address, reg[dest].I);
		reg[base].I = address + value;
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x700:
	case 0x708:
	{
		// STR Rd, [Rn, -Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x702:
	case 0x70a:
	{
		// STR Rd, [Rn, -Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x704:
	case 0x70c:
	{
		// STR Rd, [Rn, -Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x706:
	case 0x70e:
	{
		// STR Rd, [Rn, -Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x720:
	case 0x728:
	{
		// STR Rd, [Rn, -Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x722:
	case 0x72a:
	{
		// STR Rd, [Rn, -Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x724:
	case 0x72c:
	{
		// STR Rd, [Rn, -Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x726:
	case 0x72e:
	{
		// STR Rd, [Rn, -Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x780:
	case 0x788:
	{
		// STR Rd, [Rn, Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x782:
	case 0x78a:
	{
		// STR Rd, [Rn, Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x784:
	case 0x78c:
	{
		// STR Rd, [Rn, Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x786:
	case 0x78e:
	{
		// STR Rd, [Rn, Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x7a0:
	case 0x7a8:
	{
		// STR Rd, [Rn, Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x7a2:
	case 0x7aa:
	{
		// STR Rd, [Rn, Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x7a4:
	case 0x7ac:
	{
		// STR Rd, [Rn, Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x7a6:
	case 0x7ae:
	{
		// STR Rd, [Rn, Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[base].I = address;
		CPUWriteMemory(address, reg[dest].I);
		clockTicks += 2 + CPUUpdateTicksAccess32(address);
	}
	break;
	case 0x610:
	case 0x618:
	// T versions are the same
	case 0x630:
	case 0x638:
	{
		// LDR Rd, [Rn], -Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x612:
	case 0x61a:
	// T versions are the same
	case 0x632:
	case 0x63a:
	{
		// LDR Rd, [Rn], -Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x614:
	case 0x61c:
	// T versions are the same
	case 0x634:
	case 0x63c:
	{
		// LDR Rd, [Rn], -Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x616:
	case 0x61e:
	// T versions are the same
	case 0x636:
	case 0x63e:
	{
		// LDR Rd, [Rn], -Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address - value;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x690:
	case 0x698:
	// T versions are the same
	case 0x6b0:
	case 0x6b8:
	{
		// LDR Rd, [Rn], Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x692:
	case 0x69a:
	// T versions are the same
	case 0x6b2:
	case 0x6ba:
	{
		// LDR Rd, [Rn], Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x694:
	case 0x69c:
	// T versions are the same
	case 0x6b4:
	case 0x6bc:
	{
		// LDR Rd, [Rn], Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x696:
	case 0x69e:
	// T versions are the same
	case 0x6b6:
	case 0x6be:
	{
		// LDR Rd, [Rn], Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address + value;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x710:
	case 0x718:
	{
		// LDR Rd, [Rn, -Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x712:
	case 0x71a:
	{
		// LDR Rd, [Rn, -Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x714:
	case 0x71c:
	{
		// LDR Rd, [Rn, -Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x716:
	case 0x71e:
	{
		// LDR Rd, [Rn, -Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x730:
	case 0x738:
	{
		// LDR Rd, [Rn, -Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x732:
	case 0x73a:
	{
		// LDR Rd, [Rn, -Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x734:
	case 0x73c:
	{
		// LDR Rd, [Rn, -Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x736:
	case 0x73e:
	{
		// LDR Rd, [Rn, -Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x790:
	case 0x798:
	{
		// LDR Rd, [Rn, Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x792:
	case 0x79a:
	{
		// LDR Rd, [Rn, Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x794:
	case 0x79c:
	{
		// LDR Rd, [Rn, Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x796:
	case 0x79e:
	{
		// LDR Rd, [Rn, Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[dest].I = CPUReadMemory(address);
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x7b0:
	case 0x7b8:
	{
		// LDR Rd, [Rn, Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x7b2:
	case 0x7ba:
	{
		// LDR Rd, [Rn, Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x7b4:
	case 0x7bc:
	{
		// LDR Rd, [Rn, Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x7b6:
	case 0x7be:
	{
		// LDR Rd, [Rn, Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[dest].I = CPUReadMemory(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess32(address);
		if (dest == 15)
		{
			clockTicks += 2;
			reg[15].I  &= 0xFFFFFFFC;
			armNextPC	= reg[15].I;
			reg[15].I  += 4;
		}
	}
	break;
	case 0x640:
	case 0x648:
	// T versions are the same
	case 0x660:
	case 0x668:
	{
		// STRB Rd, [Rn], -Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x642:
	case 0x64a:
	// T versions are the same
	case 0x662:
	case 0x66a:
	{
		// STRB Rd, [Rn], -Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x644:
	case 0x64c:
	// T versions are the same
	case 0x664:
	case 0x66c:
	{
		// STRB Rd, [Rn], -Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address - offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x646:
	case 0x64e:
	// T versions are the same
	case 0x666:
	case 0x66e:
	{
		// STRB Rd, [Rn], -Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address - value;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6c0:
	case 0x6c8:
	// T versions are the same
	case 0x6e0:
	case 0x6e8:
	{
		// STRB Rd, [Rn], Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6c2:
	case 0x6ca:
	// T versions are the same
	case 0x6e2:
	case 0x6ea:
	{
		// STRB Rd, [Rn], Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6c4:
	case 0x6cc:
	// T versions are the same
	case 0x6e4:
	case 0x6ec:
	{
		// STR Rd, [Rn], Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address + offset;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6c6:
	case 0x6ce:
	// T versions are the same
	case 0x6e6:
	case 0x6ee:
	{
		// STRB Rd, [Rn], Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		CPUWriteByte(address, reg[dest].B.B0);
		reg[base].I = address + value;
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x740:
	case 0x748:
	{
		// STRB Rd, [Rn, -Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x742:
	case 0x74a:
	{
		// STRB Rd, [Rn, -Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x744:
	case 0x74c:
	{
		// STRB Rd, [Rn, -Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x746:
	case 0x74e:
	{
		// STRB Rd, [Rn, -Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x760:
	case 0x768:
	{
		// STRB Rd, [Rn, -Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x762:
	case 0x76a:
	{
		// STRB Rd, [Rn, -Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x764:
	case 0x76c:
	{
		// STRB Rd, [Rn, -Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x766:
	case 0x76e:
	{
		// STRB Rd, [Rn, -Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7c0:
	case 0x7c8:
	{
		// STRB Rd, [Rn, Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7c2:
	case 0x7ca:
	{
		// STRB Rd, [Rn, Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7c4:
	case 0x7cc:
	{
		// STRB Rd, [Rn, Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7c6:
	case 0x7ce:
	{
		// STRB Rd, [Rn, Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7e0:
	case 0x7e8:
	{
		// STRB Rd, [Rn, Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7e2:
	case 0x7ea:
	{
		// STRB Rd, [Rn, Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7e4:
	case 0x7ec:
	{
		// STRB Rd, [Rn, Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7e6:
	case 0x7ee:
	{
		// STRB Rd, [Rn, Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[base].I = address;
		CPUWriteByte(address, reg[dest].B.B0);
		clockTicks += 2 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x650:
	case 0x658:
	// T versions are the same
	case 0x670:
	case 0x678:
	{
		// LDRB Rd, [Rn], -Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x652:
	case 0x65a:
	// T versions are the same
	case 0x672:
	case 0x67a:
	{
		// LDRB Rd, [Rn], -Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x654:
	case 0x65c:
	// T versions are the same
	case 0x674:
	case 0x67c:
	{
		// LDRB Rd, [Rn], -Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address - offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x656:
	case 0x65e:
	// T versions are the same
	case 0x676:
	case 0x67e:
	{
		// LDRB Rd, [Rn], -Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address - value;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6d0:
	case 0x6d8:
	// T versions are the same
	case 0x6f0:
	case 0x6f8:
	{
		// LDRB Rd, [Rn], Rm, LSL #
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6d2:
	case 0x6da:
	// T versions are the same
	case 0x6f2:
	case 0x6fa:
	{
		// LDRB Rd, [Rn], Rm, LSR #
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6d4:
	case 0x6dc:
	// T versions are the same
	case 0x6f4:
	case 0x6fc:
	{
		// LDRB Rd, [Rn], Rm, ASR #
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address + offset;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x6d6:
	case 0x6de:
	// T versions are the same
	case 0x6f6:
	case 0x6fe:
	{
		// LDRB Rd, [Rn], Rm, ROR #
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address + value;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x750:
	case 0x758:
	{
		// LDRB Rd, [Rn, -Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x752:
	case 0x75a:
	{
		// LDRB Rd, [Rn, -Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x754:
	case 0x75c:
	{
		// LDRB Rd, [Rn, -Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x756:
	case 0x75e:
	{
		// LDRB Rd, [Rn, -Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x770:
	case 0x778:
	{
		// LDRB Rd, [Rn, -Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x772:
	case 0x77a:
	{
		// LDRB Rd, [Rn, -Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x774:
	case 0x77c:
	{
		// LDRB Rd, [Rn, -Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x776:
	case 0x77e:
	{
		// LDRB Rd, [Rn, -Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I - value;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7d0:
	case 0x7d8:
	{
		// LDRB Rd, [Rn, Rm, LSL #]
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7d2:
	case 0x7da:
	{
		// LDRB Rd, [Rn, Rm, LSR #]
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7d4:
	case 0x7dc:
	{
		// LDRB Rd, [Rn, Rm, ASR #]
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7d6:
	case 0x7de:
	{
		// LDRB Rd, [Rn, Rm, ROR #]
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[dest].I = CPUReadByte(address);
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7f0:
	case 0x7f8:
	{
		// LDRB Rd, [Rn, Rm, LSL #]!
		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7f2:
	case 0x7fa:
	{
		// LDRB Rd, [Rn, Rm, LSR #]!
		int shift	= (opcode >> 7) & 31;
		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7f4:
	case 0x7fc:
	{
		// LDRB Rd, [Rn, Rm, ASR #]!
		int shift = (opcode >> 7) & 31;
		int offset;
		if (shift)
			offset = (int)((s32)reg[opcode & 15].I >> shift);
		else if (reg[opcode & 15].I & 0x80000000)
			offset = 0xFFFFFFFF;
		else
			offset = 0;
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + offset;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
	case 0x7f6:
	case 0x7fe:
	{
		// LDRB Rd, [Rn, Rm, ROR #]!
		int shift = (opcode >> 7) & 31;
		u32 value = reg[opcode & 15].I;
		if (shift)
		{
			ROR_VALUE;
		}
		else
		{
			RCR_VALUE;
		}
		int dest	= (opcode >> 12) & 15;
		int base	= (opcode >> 16) & 15;
		u32 address = reg[base].I + value;
		reg[dest].I = CPUReadByte(address);
		if (dest != base)
			reg[base].I = address;
		clockTicks += 3 + CPUUpdateTicksAccess16(address);
	}
	break;
#define STMW_REG(val, num) \
	if (opcode & (val)) { \
		CPUWriteMemory(address, reg[(num)].I); \
		if (!offset) { \
			reg[base].I = temp; \
			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
			offset		= 1; \
		} else { \
			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
		} \
		address += 4; \
	}
#define STM_REG(val, num) \
	if (opcode & (val)) { \
		CPUWriteMemory(address, reg[(num)].I); \
		if (!offset) { \
			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
			offset		= 1; \
		} else { \
			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
		} \
		address += 4; \
	}

		CASE_16(0x800)
		// STMDA Rn, {Rlist}
		{
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			STM_REG(256, 8);
			STM_REG(512, 9);
			STM_REG(1024, 10);
			STM_REG(2048, 11);
			STM_REG(4096, 12);
			STM_REG(8192, 13);
			STM_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x820)
		{
			// STMDA Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			STMW_REG(256, 8);
			STMW_REG(512, 9);
			STMW_REG(1024, 10);
			STMW_REG(2048, 11);
			STMW_REG(4096, 12);
			STMW_REG(8192, 13);
			STMW_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
				reg[base].I = temp;
			}
		}
		break;
		CASE_16(0x840)
		{
			// STMDA Rn, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);

			if (armMode == 0x11)
			{
				STM_REG(256, R8_FIQ);
				STM_REG(512, R9_FIQ);
				STM_REG(1024, R10_FIQ);
				STM_REG(2048, R11_FIQ);
				STM_REG(4096, R12_FIQ);
			}
			else
			{
				STM_REG(256, 8);
				STM_REG(512, 9);
				STM_REG(1024, 10);
				STM_REG(2048, 11);
				STM_REG(4096, 12);
			}

			if (armMode != 0x10 && armMode != 0x1f)
			{
				STM_REG(8192, R13_USR);
				STM_REG(16384, R14_USR);
			}
			else
			{
				STM_REG(8192, 13);
				STM_REG(16384, 14);
			}

			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x860)
		{
			// STMDA Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);

			if (armMode == 0x11)
			{
				STMW_REG(256, R8_FIQ);
				STMW_REG(512, R9_FIQ);
				STMW_REG(1024, R10_FIQ);
				STMW_REG(2048, R11_FIQ);
				STMW_REG(4096, R12_FIQ);
			}
			else
			{
				STMW_REG(256, 8);
				STMW_REG(512, 9);
				STMW_REG(1024, 10);
				STMW_REG(2048, 11);
				STMW_REG(4096, 12);
			}

			if (armMode != 0x10 && armMode != 0x1f)
			{
				STMW_REG(8192, R13_USR);
				STMW_REG(16384, R14_USR);
			}
			else
			{
				STMW_REG(8192, 13);
				STMW_REG(16384, 14);
			}

			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
				reg[base].I = temp;
			}
		}
		break;

		CASE_16(0x880)
		{
			// STMIA Rn, {Rlist}
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			STM_REG(256, 8);
			STM_REG(512, 9);
			STM_REG(1024, 10);
			STM_REG(2048, 11);
			STM_REG(4096, 12);
			STM_REG(8192, 13);
			STM_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x8a0)
		{
			// STMIA Rn!, {Rlist}
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
			                                cpuBitsSet[(opcode >> 8) & 255]);
			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			STMW_REG(256, 8);
			STMW_REG(512, 9);
			STMW_REG(1024, 10);
			STMW_REG(2048, 11);
			STMW_REG(4096, 12);
			STMW_REG(8192, 13);
			STMW_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
				{
					reg[base].I = temp;
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				}
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x8c0)
		{
			// STMIA Rn, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			if (armMode == 0x11)
			{
				STM_REG(256, R8_FIQ);
				STM_REG(512, R9_FIQ);
				STM_REG(1024, R10_FIQ);
				STM_REG(2048, R11_FIQ);
				STM_REG(4096, R12_FIQ);
			}
			else
			{
				STM_REG(256, 8);
				STM_REG(512, 9);
				STM_REG(1024, 10);
				STM_REG(2048, 11);
				STM_REG(4096, 12);
			}
			if (armMode != 0x10 && armMode != 0x1f)
			{
				STM_REG(8192, R13_USR);
				STM_REG(16384, R14_USR);
			}
			else
			{
				STM_REG(8192, 13);
				STM_REG(16384, 14);
			}
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x8e0)
		{
			// STMIA Rn!, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
			                                cpuBitsSet[(opcode >> 8) & 255]);
			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			if (armMode == 0x11)
			{
				STMW_REG(256, R8_FIQ);
				STMW_REG(512, R9_FIQ);
				STMW_REG(1024, R10_FIQ);
				STMW_REG(2048, R11_FIQ);
				STMW_REG(4096, R12_FIQ);
			}
			else
			{
				STMW_REG(256, 8);
				STMW_REG(512, 9);
				STMW_REG(1024, 10);
				STMW_REG(2048, 11);
				STMW_REG(4096, 12);
			}
			if (armMode != 0x10 && armMode != 0x1f)
			{
				STMW_REG(8192, R13_USR);
				STMW_REG(16384, R14_USR);
			}
			else
			{
				STMW_REG(8192, 13);
				STMW_REG(16384, 14);
			}
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
				{
					reg[base].I = temp;
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				}
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;

		CASE_16(0x900)
		{
			// STMDB Rn, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			STM_REG(256, 8);
			STM_REG(512, 9);
			STM_REG(1024, 10);
			STM_REG(2048, 11);
			STM_REG(4096, 12);
			STM_REG(8192, 13);
			STM_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x920)
		{
			// STMDB Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			STMW_REG(256, 8);
			STMW_REG(512, 9);
			STMW_REG(1024, 10);
			STMW_REG(2048, 11);
			STMW_REG(4096, 12);
			STMW_REG(8192, 13);
			STMW_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
				reg[base].I = temp;
			}
		}
		break;
		CASE_16(0x940)
		{
			// STMDB Rn, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);

			if (armMode == 0x11)
			{
				STM_REG(256, R8_FIQ);
				STM_REG(512, R9_FIQ);
				STM_REG(1024, R10_FIQ);
				STM_REG(2048, R11_FIQ);
				STM_REG(4096, R12_FIQ);
			}
			else
			{
				STM_REG(256, 8);
				STM_REG(512, 9);
				STM_REG(1024, 10);
				STM_REG(2048, 11);
				STM_REG(4096, 12);
			}

			if (armMode != 0x10 && armMode != 0x1f)
			{
				STM_REG(8192, R13_USR);
				STM_REG(16384, R14_USR);
			}
			else
			{
				STM_REG(8192, 13);
				STM_REG(16384, 14);
			}

			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x960)
		{
			// STMDB Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;

			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);

			if (armMode == 0x11)
			{
				STMW_REG(256, R8_FIQ);
				STMW_REG(512, R9_FIQ);
				STMW_REG(1024, R10_FIQ);
				STMW_REG(2048, R11_FIQ);
				STMW_REG(4096, R12_FIQ);
			}
			else
			{
				STMW_REG(256, 8);
				STMW_REG(512, 9);
				STMW_REG(1024, 10);
				STMW_REG(2048, 11);
				STMW_REG(4096, 12);
			}

			if (armMode != 0x10 && armMode != 0x1f)
			{
				STMW_REG(8192, R13_USR);
				STMW_REG(16384, R14_USR);
			}
			else
			{
				STMW_REG(8192, 13);
				STMW_REG(16384, 14);
			}

			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
				reg[base].I = temp;
			}
		}
		break;

		CASE_16(0x980)
		// STMIB Rn, {Rlist}
		{
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			STM_REG(256, 8);
			STM_REG(512, 9);
			STM_REG(1024, 10);
			STM_REG(2048, 11);
			STM_REG(4096, 12);
			STM_REG(8192, 13);
			STM_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x9a0)
		{
			// STMIB Rn!, {Rlist}
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
			                                cpuBitsSet[(opcode >> 8) & 255]);
			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			STMW_REG(256, 8);
			STMW_REG(512, 9);
			STMW_REG(1024, 10);
			STMW_REG(2048, 11);
			STMW_REG(4096, 12);
			STMW_REG(8192, 13);
			STMW_REG(16384, 14);
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
				{
					reg[base].I = temp;
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				}
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x9c0)
		{
			// STMIB Rn, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			STM_REG(1, 0);
			STM_REG(2, 1);
			STM_REG(4, 2);
			STM_REG(8, 3);
			STM_REG(16, 4);
			STM_REG(32, 5);
			STM_REG(64, 6);
			STM_REG(128, 7);
			if (armMode == 0x11)
			{
				STM_REG(256, R8_FIQ);
				STM_REG(512, R9_FIQ);
				STM_REG(1024, R10_FIQ);
				STM_REG(2048, R11_FIQ);
				STM_REG(4096, R12_FIQ);
			}
			else
			{
				STM_REG(256, 8);
				STM_REG(512, 9);
				STM_REG(1024, 10);
				STM_REG(2048, 11);
				STM_REG(4096, 12);
			}
			if (armMode != 0x10 && armMode != 0x1f)
			{
				STM_REG(8192, R13_USR);
				STM_REG(16384, R14_USR);
			}
			else
			{
				STM_REG(8192, 13);
				STM_REG(16384, 14);
			}
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;
		CASE_16(0x9e0)
		{
			// STMIB Rn!, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
			                                cpuBitsSet[(opcode >> 8) & 255]);
			STMW_REG(1, 0);
			STMW_REG(2, 1);
			STMW_REG(4, 2);
			STMW_REG(8, 3);
			STMW_REG(16, 4);
			STMW_REG(32, 5);
			STMW_REG(64, 6);
			STMW_REG(128, 7);
			if (armMode == 0x11)
			{
				STMW_REG(256, R8_FIQ);
				STMW_REG(512, R9_FIQ);
				STMW_REG(1024, R10_FIQ);
				STMW_REG(2048, R11_FIQ);
				STMW_REG(4096, R12_FIQ);
			}
			else
			{
				STMW_REG(256, 8);
				STMW_REG(512, 9);
				STMW_REG(1024, 10);
				STMW_REG(2048, 11);
				STMW_REG(4096, 12);
			}
			if (armMode != 0x10 && armMode != 0x1f)
			{
				STMW_REG(8192, R13_USR);
				STMW_REG(16384, R14_USR);
			}
			else
			{
				STMW_REG(8192, 13);
				STMW_REG(16384, 14);
			}
			if (opcode & 32768)
			{
				CPUWriteMemory(address, reg[15].I + 4);
				if (!offset)
				{
					reg[base].I = temp;
					clockTicks += 1 + CPUUpdateTicksAccess32(address);
				}
				else
					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
			}
		}
		break;

#define LDM_REG(val, num) \
	if (opcode & (val)) { \
		reg[(num)].I = CPUReadMemory(address); \
		if (offset) \
			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
		else { \
			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
			offset		= 1; \
		} \
		address += 4; \
	}

		CASE_16(0x810)
		{
			// LDMDA Rn, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
		}
		break;
		CASE_16(0x830)
		{
			// LDMDA Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
			if (!(opcode & (1 << base)))
				reg[base].I = temp;
		}
		break;
		CASE_16(0x850)
		{
			// LDMDA Rn, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}
			}
		}
		break;
		CASE_16(0x870)
		{
			// LDMDA Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (temp + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				if (!(opcode & (1 << base)))
					reg[base].I = temp;

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}

				if (!(opcode & (1 << base)))
					reg[base].I = temp;
			}
		}
		break;

		CASE_16(0x890)
		{
			// LDMIA Rn, {Rlist}
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
		}
		break;
		CASE_16(0x8b0)
		{
			// LDMIA Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I +
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
			if (!(opcode & (1 << base)))
				reg[base].I = temp;
		}
		break;
		CASE_16(0x8d0)
		{
			// LDMIA Rn, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}
			}
		}
		break;
		CASE_16(0x8f0)
		{
			// LDMIA Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I +
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = reg[base].I & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				if (!(opcode & (1 << base)))
					reg[base].I = temp;

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}

				if (!(opcode & (1 << base)))
					reg[base].I = temp;
			}
		}
		break;

		CASE_16(0x910)
		{
			// LDMDB Rn, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
		}
		break;
		CASE_16(0x930)
		{
			// LDMDB Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
			if (!(opcode & (1 << base)))
				reg[base].I = temp;
		}
		break;
		CASE_16(0x950)
		{
			// LDMDB Rn, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}
			}
		}
		break;
		CASE_16(0x970)
		{
			// LDMDB Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I -
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = temp & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				if (!(opcode & (1 << base)))
					reg[base].I = temp;

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}

				if (!(opcode & (1 << base)))
					reg[base].I = temp;
			}
		}
		break;

		CASE_16(0x990)
		{
			// LDMIB Rn, {Rlist}
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
		}
		break;
		CASE_16(0x9b0)
		{
			// LDMIB Rn!, {Rlist}
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I +
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			LDM_REG(1, 0);
			LDM_REG(2, 1);
			LDM_REG(4, 2);
			LDM_REG(8, 3);
			LDM_REG(16, 4);
			LDM_REG(32, 5);
			LDM_REG(64, 6);
			LDM_REG(128, 7);
			LDM_REG(256, 8);
			LDM_REG(512, 9);
			LDM_REG(1024, 10);
			LDM_REG(2048, 11);
			LDM_REG(4096, 12);
			LDM_REG(8192, 13);
			LDM_REG(16384, 14);
			if (opcode & 32768)
			{
				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
				armNextPC  = reg[15].I;
				reg[15].I += 4;
			}
			if (!(opcode & (1 << base)))
				reg[base].I = temp;
		}
		break;
		CASE_16(0x9d0)
		{
			// LDMIB Rn, {Rlist}^
			int base	= (opcode & 0x000F0000) >> 16;
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}
			}
		}
		break;
		CASE_16(0x9f0)
		{
			// LDMIB Rn!, {Rlist}^
			int base = (opcode & 0x000F0000) >> 16;
			u32 temp = reg[base].I +
			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
			clockTicks += 2;
			int offset = 0;
			if (opcode & 0x8000)
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);
				LDM_REG(256, 8);
				LDM_REG(512, 9);
				LDM_REG(1024, 10);
				LDM_REG(2048, 11);
				LDM_REG(4096, 12);
				LDM_REG(8192, 13);
				LDM_REG(16384, 14);

				reg[15].I = CPUReadMemory(address);
				if (!offset)
					clockTicks += 2 + CPUUpdateTicksAccess32(address);
				else
					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);

				if (!(opcode & (1 << base)))
					reg[base].I = temp;

				CPUSwitchMode(reg[17].I & 0x1f, false);
				if (armState)
				{
					armNextPC = reg[15].I & 0xFFFFFFFC;
					reg[15].I = armNextPC + 4;
				}
				else
				{
					armNextPC = reg[15].I & 0xFFFFFFFE;
					reg[15].I = armNextPC + 2;
				}
			}
			else
			{
				LDM_REG(1, 0);
				LDM_REG(2, 1);
				LDM_REG(4, 2);
				LDM_REG(8, 3);
				LDM_REG(16, 4);
				LDM_REG(32, 5);
				LDM_REG(64, 6);
				LDM_REG(128, 7);

				if (armMode == 0x11)
				{
					LDM_REG(256, R8_FIQ);
					LDM_REG(512, R9_FIQ);
					LDM_REG(1024, R10_FIQ);
					LDM_REG(2048, R11_FIQ);
					LDM_REG(4096, R12_FIQ);
				}
				else
				{
					LDM_REG(256, 8);
					LDM_REG(512, 9);
					LDM_REG(1024, 10);
					LDM_REG(2048, 11);
					LDM_REG(4096, 12);
				}

				if (armMode != 0x10 && armMode != 0x1f)
				{
					LDM_REG(8192, R13_USR);
					LDM_REG(16384, R14_USR);
				}
				else
				{
					LDM_REG(8192, 13);
					LDM_REG(16384, 14);
				}

				if (!(opcode & (1 << base)))
					reg[base].I = temp;
			}
		}
		break;
		CASE_256(0xa00)
		{
			// B <offset>
			clockTicks += 3;
			int offset = opcode & 0x00FFFFFF;
			if (offset & 0x00800000)
			{
				offset |= 0xFF000000;
			}
			offset	 <<= 2;
			reg[15].I += offset;
			armNextPC  = reg[15].I;
			reg[15].I += 4;
		}
		break;
		CASE_256(0xb00)
		{
			// BL <offset>
			clockTicks += 3;
			int offset = opcode & 0x00FFFFFF;
			if (offset & 0x00800000)
			{
				offset |= 0xFF000000;
			}
			offset	 <<= 2;
			reg[14].I  = reg[15].I - 4;
			reg[15].I += offset;
			armNextPC  = reg[15].I;
			reg[15].I += 4;
		}
		break;
		CASE_256(0xf00)
		// SWI <comment>
		clockTicks += 3;
		CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
		break;
#ifdef GP_SUPPORT
	case 0xe11:
	case 0xe13:
	case 0xe15:
	case 0xe17:
	case 0xe19:
	case 0xe1b:
	case 0xe1d:
	case 0xe1f:
		// MRC
		break;
	case 0xe01:
	case 0xe03:
	case 0xe05:
	case 0xe07:
	case 0xe09:
	case 0xe0b:
	case 0xe0d:
	case 0xe0f:
		// MRC
		break;
#endif
	default:
#ifdef GBA_LOGGING
		if (systemVerbose & VERBOSE_UNDEFINED)
			log("Undefined ARM instruction %08x at %08x\n", opcode,
			    armNextPC - 4);
#endif
		CPUUndefinedException();
		break;
		// END
	}
}
